% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.

%%% @author CA Meijer
%%% @copyright 2012 CA Meijer
%%% @doc This module exposes functions to map Nimbula JSON objects to Erlang
%%%      records and vice-versa. The supported records may be found in
%%%      the "nimbula_records.hrl" header in the include directory.
%%% @end

-module(nimbula_json).

%% Exported Functions
-export([record_to_json/2,
		 json_to_record/2,
		 json_to_record_list/2]).

%% API
record_to_json({Record, RecordFields}, RecordTuple) ->
	[Record|RecordValues] = tuple_to_list(RecordTuple),
	MochiJsonTuple = {struct, make_json_tuple(RecordFields, RecordValues, [])},
	iolist_to_binary(mochijson2:encode(MochiJsonTuple)).

json_to_record({Record, RecordFields}, Json) ->
	{struct, KeyValuePairs} = mochijson2:decode(Json),
	list_to_tuple(extract_fields(RecordFields, KeyValuePairs, [Record])).

json_to_record_list({Record, RecordFields}, JsonList) ->
	{struct, KeyValuesList} = mochijson2:decode(JsonList),
	[{<<"result">>, MochiObjects}] = KeyValuesList,
	Objects = [KeyValuePairs || {struct, KeyValuePairs} <- MochiObjects],
	[list_to_tuple(extract_fields(RecordFields, Object, [Record])) || Object <- Objects].
	
%% Local Functions
extract_fields([], _KeyValuePairs, Result) ->
	Result;
extract_fields([Field|Tail], KeyValuePairs, Result) ->
	Value = extract_field(Field, KeyValuePairs),
	extract_fields(Tail, KeyValuePairs, Result ++ [Value]).

extract_field(_Field, []) ->
	undefined;
extract_field(Field, [{Key, Value}|KeyValuesTail]) ->
	KeyAtom = list_to_atom(unicode:characters_to_list(Key)),
	case KeyAtom of
		Field ->
			Value;
		_ ->
			extract_field(Field, KeyValuesTail)
	end.
	
make_json_tuple([], [], Result) ->
	Result;
make_json_tuple([_Key|KeyTail], [null|ValueTail], Result) ->
	make_json_tuple(KeyTail, ValueTail, Result);
make_json_tuple([_Key|KeyTail], [undefined|ValueTail], Result) ->
	make_json_tuple(KeyTail, ValueTail, Result);
make_json_tuple([Key|KeyTail], [Value|ValueTail], Result) ->
	make_json_tuple(KeyTail, ValueTail, Result ++ [{atom_to_binary(Key, utf8), Value}]).
